package com.youlu.campus.web.vote.service;

import com.google.common.collect.Lists;
import com.youlu.campus.base.exception.BusinessException;
import com.youlu.campus.entity.UniversityInfo;
import com.youlu.campus.entity.UserInfoExtend;
import com.youlu.campus.entity.UserPO;
import com.youlu.campus.entity.VO.req.CheckMobileVO;
import com.youlu.campus.entity.WechatH5UserPO;
import com.youlu.campus.entity.vote.UserVotePointEntity;
import com.youlu.campus.entity.vote.VoteConstant;
import com.youlu.campus.entity.vote.VoteOrganizationInfo;
import com.youlu.campus.entity.vote.VoteSimpleActivityEntity;
import com.youlu.campus.entity.vote.dto.*;
import com.youlu.campus.entity.vote.vo.*;
import com.youlu.campus.service.activity.WechatMiniQaService;
import com.youlu.campus.service.auth.WechatH5UserService;
import com.youlu.campus.service.visitor.UserInfoExtendService;
import com.youlu.campus.service.vote.*;
import com.youlu.campus.service.vote.convert.VoteOrgConvert;
import com.youlu.campus.web.common.base.RequestContext;
import com.youlu.campus.web.user.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Tuple;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author : [dengbo]
 * @className : ActivityVoteHomeService
 * @description : [投票活动首页]
 * @createTime : [2022/6/30 10:44]
 */
@Service
@Slf4j
public class ActivityVoteHomeService {
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private ActivityVoteRedisService activityVoteRedisService;
    @Autowired
    private VoteOrgConvert voteOrgConvert;
    @Autowired
    private WechatH5UserService wechatH5UserService;
    @Autowired
    private UserVoteService userVoteService;
    @Autowired
    private VoteOrganizationService voteOrganizationService;
    @Autowired
    private SimpleActivityService simpleActivityService;
    @Autowired
    private WechatMiniQaService wechatMiniQaService;
    @Autowired
    private UserInfoExtendService userInfoExtendService;
    @Autowired
    private UserService userService;
    @Autowired
    private ActivityVoteService activityVoteService;


    /**
     * 获取组织投票分页排行信息
     * @param dto
     * @return
     */
    public OrgVoteResultVo getOrgVoteRankPage(VoteHomeSearchDTO dto) {
        String activityId = dto.getActivityId();
        List<String> fields = Lists.newArrayList("id", "type", "name", "detail", "wechatAuthorizationImageUrl", "wechatAuthorizationDesc",
                "countryRankName", "activityRule", "hiddenRule", "hasProvinceRank", "provinceRankName",
                "provinceSubTile", "countryRankSubTile", "startTime", "endTime", "orgTypeId", "headerImageUrl");
        // 1、查询活动信息
        VoteSimpleActivityEntity activityInfo = simpleActivityService.findFieldsById(activityId, fields, VoteSimpleActivityEntity.class);
        if (activityInfo == null) {
            throw new BusinessException("活动信息不存在");
        }
        // 2、查询组织分类信息
        String orgTypeId = activityInfo.getOrgTypeId();
        if (orgTypeId == null) {
            throw new BusinessException("组织分类信息不存在");
        }
        dto.setOrgTypeId(orgTypeId);
        // 默认北京市
        dto.setProvinceCode(VoteConstant.DEFAULT_PRO_CODE);
        OrgVoteResultVo resultVo = new OrgVoteResultVo();
        // 3、设置活动信息信息
        VoteActivityInfoVo voteActivityToVo = voteOrgConvert.voteActivityToVo(activityInfo);
        resultVo.setActivityInfo(voteActivityToVo);
        // 4、添加统计信息
        if (dto.getShowStatistics()) {
            resultVo.setStatisticsInfo(getVoteStatistics(dto));
        }
        // 5、通过输入学校名称/编码搜索
        if (StringUtils.isNotBlank(dto.getKeyword())) {
            resultVo.setPageInfo(getOrgRankSearch(dto));
            return resultVo;
        }
        // 6、设置排行榜数据
        resultVo.setPageInfo(getOrgRankList(dto, resultVo));
        // 7、发放数据,每日发放3个
        userVoteService.perDayVoteReceive(dto, VoteConstant.PER_DAY_RECEIVE_NUM);
        return resultVo;
    }

    /**
     * 获取投票统计信息
     * @param dto
     * @return
     */
    public VoteStatisticsInfoVo getVoteStatistics(VoteHomeSearchDTO dto) {
        VoteStatisticsInfoVo statisticsInfoVo = new VoteStatisticsInfoVo();
        statisticsInfoVo.setTotalVoteNum(activityVoteRedisService.getTotalVoteNum(dto.getActivityId()));
        statisticsInfoVo.setTotalPV(activityVoteRedisService.getActivityPV(dto.getActivityId()));
        statisticsInfoVo.setJoinSchoolNum(activityVoteRedisService.getAllVoteSchoolNum(dto.getActivityId()));
        return statisticsInfoVo;
    }

    /**
     *  组织搜索
     * @param dto
     * @return
     */
    public Page<OrgVoteInfoVo> getOrgRankSearch(VoteHomeSearchDTO dto) {
        boolean isOrgCode = StringUtils.isNumeric(dto.getKeyword());
        // 通过选择编码搜索
        if (isOrgCode) {
            dto.setOrgCode(dto.getKeyword());
            return getOrgCodeSearchRankList(dto);
        }
        if (dto.getKeyword().length() < VoteConstant.SEARCH_SCHOOL_DEFAULT_CHART_NUM) {
            throw new BusinessException("至少输入4个字符");
        }
        dto.setOrgName(dto.getKeyword());
        return getOrgNameSearchRankList(dto);
    }

    /**
     * 组织排行榜列表
     * @param dto
     * @param resultVo
     * @return
     */
    public Page<OrgVoteInfoVo> getOrgRankList(VoteHomeSearchDTO dto, OrgVoteResultVo resultVo) {
        Pair<Long, Set<Tuple>> rankList;
        // 更新用户学校排名信息
        updateUserSchoolRank(dto, resultVo);
        // 获取排行榜
        if (VoteHomeSearchDTO.ALL.equals(dto.getType())) {
            // 全国榜
            rankList = activityVoteRedisService.getAllOrgPageInfo(dto.getActivityId(), dto.getPage(), dto.getPageSize());
        } else {
            String provinceCode = dto.getProvinceCode();
            // 省榜
            rankList = activityVoteRedisService.getProvinceOrgPageInfo(dto.getActivityId(), provinceCode, dto.getPage(), dto.getPageSize());
        }
        long count = rankList.getLeft();
        // 解析数据
        PageRequest pageRequest = PageRequest.of(dto.getPage() - 1, dto.getPageSize());
        // 解析排行榜数据
        List<OrgVoteInfoVo> result = getRankInfoList(rankList.getRight(), dto, pageRequest.getOffset());
        return PageableExecutionUtils.getPage(result, pageRequest, () -> count);
    }

    /**
     * 将缓存的排行榜信息转化为排行榜
     * @param rankSet
     * @param dto
     * @param start
     * @return
     */
    public List<OrgVoteInfoVo> getRankInfoList(Set<Tuple> rankSet, VoteHomeSearchDTO dto, long start) {
        Set<String> orgCodeList = rankSet.stream().map(Tuple::getElement).collect(Collectors.toSet());
        List<VoteOrganizationInfo> orgList = voteOrganizationService.getOrgListByOrgCodeList(dto.getOrgTypeId(), orgCodeList);
        List<OrgVoteInfoVo> result = voteOrgConvert.voteOrgToVo(rankSet, orgList, start);
        return result;
    }

    /**
     * 按照组织编码搜索
     * @param dto
     * @return
     */
    public Page<OrgVoteInfoVo> getOrgCodeSearchRankList(VoteHomeSearchDTO dto) {
        VoteOrganizationInfo info = voteOrganizationService.getOrgInfoByOrgCode(dto.getOrgTypeId(), dto.getOrgCode());
        PageRequest pageRequest = PageRequest.of(dto.getPage() - 1, dto.getPageSize());
        if (info == null) {
            return PageableExecutionUtils.getPage(Collections.emptyList(), pageRequest, () -> 0);
        }
        Triple<String, Long, Double> searchData = VoteHomeSearchDTO.ALL.equals(dto.getType()) ? activityVoteRedisService.getAllUserVoteRankAndScore(dto.getActivityId(), info.getOrgCode())
                : activityVoteRedisService.getUserProvinceSchoolVoteRankAndScore(dto.getActivityId(), info.getProvinceCode(), info.getOrgCode());
        OrgVoteInfoVo vo = voteOrgConvert.orgToUserOrgVo(info, searchData.getMiddle(), searchData.getRight());
        // 解析排行榜数据
        List<OrgVoteInfoVo> result = Lists.newArrayList(vo);
        // 解析数据
        return PageableExecutionUtils.getPage(result, pageRequest, () -> 1);
    }

    /**
     * 按照组织名称搜索
     * @param dto
     * @return
     */
    public Page<OrgVoteInfoVo> getOrgNameSearchRankList(VoteHomeSearchDTO dto) {
        List<VoteOrganizationInfo> infos = voteOrganizationService.getOrgInfoByOrgName(dto.getOrgTypeId(), dto.getOrgName());
        long count = infos.size();
        List<OrgVoteInfoVo> list = Lists.newArrayListWithExpectedSize((int) count);
        for (VoteOrganizationInfo info : infos) {
            Triple<String, Long, Double> searchData = VoteHomeSearchDTO.ALL.equals(dto.getType()) ? activityVoteRedisService.getAllUserVoteRankAndScore(dto.getActivityId(), info.getOrgCode()) :
                    activityVoteRedisService.getUserProvinceSchoolVoteRankAndScore(dto.getActivityId(), info.getProvinceCode(), info.getOrgCode());
            OrgVoteInfoVo vo = voteOrgConvert.orgToUserOrgVo(info, searchData.getMiddle(), searchData.getRight());
            list.add(vo);
        }
        PageRequest pageRequest = PageRequest.of(dto.getPage() - 1, dto.getPageSize());
        long skip = pageRequest.getOffset();
        List<OrgVoteInfoVo> result = list.stream().sorted(Comparator.comparing(OrgVoteInfoVo::getVoteNum).reversed()).skip(skip).limit(dto.getPageSize()).collect(Collectors.toList());
        return PageableExecutionUtils.getPage(result, pageRequest, () -> count);
    }

    /**
     * 更新用户学校排行榜
     * @param dto
     * @param resultVo
     */
    public void updateUserSchoolRank(VoteHomeSearchDTO dto, OrgVoteResultVo resultVo) {
        if (dto.getUserId() == null || !dto.getShowButtomRank()) {
            return;
        }
        UserPO userPO = dto.getUserPO();
        // 查询用户学校信息
//        UserVotePointEntity userVotePoint = userVoteService.findUserVotePoint(dto.getActivityId(), dto.getUserId());
//        if (userVotePoint == null || userVotePoint.getUniversityId() == null) {
//            log.info("updateUserSchoolRank,join info is null userId:{}", dto.getUserId());
//            return;
//        }
        // 学校Id
        String schoolId = userPO.getUniversityId();
        UserInfoExtend userInfoExtend = userInfoExtendService.findByUserIdAndAppId(userPO);
        if (userInfoExtend != null) {
            schoolId = userInfoExtend.getUniversityId();
        }
        if (schoolId == null) {
            log.info("updateUserSchoolRank,school id  is null userId:{}", dto.getUserId());
            return;
        }
        VoteOrganizationInfo organizationInfo = voteOrganizationService.getOrgInfoByOrgId(dto.getOrgTypeId(), schoolId);
        if (organizationInfo == null) {
            log.info("updateUserSchoolRank,org info is null userId:{}", dto.getUserId());
            return;
        }
        String provinceCode = organizationInfo.getProvinceCode();
        String orgCode = organizationInfo.getOrgCode();
        // 查询学校信息
        Triple<String, Long, Double> rankInfo = VoteHomeSearchDTO.ALL.equals(dto.getType()) ?
                activityVoteRedisService.getAllUserVoteRankAndScore(dto.getActivityId(), orgCode) :
                activityVoteRedisService.getUserProvinceSchoolVoteRankAndScore(dto.getActivityId(), provinceCode, orgCode);
        long score = rankInfo.getRight() == null ? 0 : rankInfo.getRight().longValue();
        // 是否参与活动，是否有排行，有则表示参与
        if (rankInfo.getMiddle() != null && score > 0) {
            // 获取用户排行信息
            OrgVoteInfoVo userVoteInfo = voteOrgConvert.orgToUserOrgVo(organizationInfo, rankInfo.getMiddle(), rankInfo.getRight());
            dto.setProvinceCode(provinceCode);
            dto.setOrgCode(orgCode);
            resultVo.setOrgVoteInfo(userVoteInfo);
        }
    }

    /**
     * 获取用户投票排行榜
     * @param dto
     * @return
     */
    public UserVoteRankResultVo getUserVoteRankPage(UserVoteSearchDTO dto) {
        UserVoteRankResultVo resultVo = new UserVoteRankResultVo();
        // 1、查询活动
        String activityId = dto.getActivityId();
        List<String> fields = Lists.newArrayList("id", "type", "name", "detail", "userRankName", "userRankSubTile", "startTime", "endTime", "orgTypeId", "headerImageUrl", "userHeaderImageUrl");
        VoteSimpleActivityEntity activityInfo = simpleActivityService.findFieldsById(activityId, fields, VoteSimpleActivityEntity.class);
        if (activityInfo == null) {
            throw new BusinessException("活动信息不存在");
        }
        VoteActivityInfoVo voteActivityToVo = voteOrgConvert.voteActivityToVo(activityInfo);
        resultVo.setActivityInfo(voteActivityToVo);
        // 2、查询分类信息
        if (activityInfo.getOrgTypeId() == null) {
            throw new BusinessException("组织分类信息不存在");
        }
        // 3、查询用户用户榜
        Pair<Long, Set<Tuple>> list = activityVoteRedisService.getUserPersonalPageInfo(activityId, dto.getPage(), dto.getPageSize());
        resultVo.setPageInfo(getUserRankList(dto, list));
        String userId = dto.getUserId();
        // 4、查询用户个人投票排名
        Triple<String, Long, Double> rank = activityVoteRedisService.getUserPersonalVoteRankAndScore(activityId, userId);
        // 5、获取用户排行信息,无论有无用户信息都展示
        UserVoteInfoVo userVoteInfo = voteOrgConvert.acUserToOrgVo(dto.getUserPO(), rank.getMiddle(), rank.getRight());
        resultVo.setUserVoteInfo(userVoteInfo);
        return resultVo;
    }

    public Page<UserVoteInfoVo> getUserRankList(UserVoteSearchDTO dto, Pair<Long, Set<Tuple>> rank) {
        // 查询学校信息
        Set<Tuple> rankList = rank.getRight();
        Set<String> userAidList = rankList.stream().map(Tuple::getElement).collect(Collectors.toSet());
        List<WechatH5UserPO> userList = wechatH5UserService.getWechatUserList(userAidList);
        // 解析数据
        PageRequest pageRequest = PageRequest.of(dto.getPage() - 1, dto.getPageSize());
        List<UserVoteInfoVo> result = voteOrgConvert.voteUserToVo(rankList, userList, pageRequest.getOffset());
        return PageableExecutionUtils.getPage(result, pageRequest, () -> rank.getLeft());
    }


    /**
     * 用户投票
     * @param dto
     * @return
     */
    public UserVoteResultVo userOrgVote(VotePointOpDTO dto) {
        UserVoteResultVo resultVo = new UserVoteResultVo();
        resultVo.setType(UserVoteResultVo.SUCCESS);
        resultVo.setTitle("投票成功");
        List<String> fields = Lists.newArrayList("id", "startTime", "endTime", "orgTypeId");
        VoteSimpleActivityEntity activityInfo = simpleActivityService.findFieldsById(dto.getActivityId(), fields, VoteSimpleActivityEntity.class);
        if (activityInfo == null) {
            throw new BusinessException("活动信息不存在");
        }
        Date date = new Date();
        if (activityInfo.getStartTime() != null && date.before(activityInfo.getStartTime())) {
            throw new BusinessException("活动未开始");
        }
        if (activityInfo.getEndTime() != null && date.after(activityInfo.getEndTime())) {
            resultVo.setType(UserVoteResultVo.ALREADY_END);
            resultVo.setTitle("活动已结束");
            return resultVo;
        }
        UserVotePointEntity point = userVoteService.findUserVotePoint(dto.getActivityId(), dto.getUserId());
        if (point == null || point.getTotalNum() <= 0) {
            resultVo.setType(UserVoteResultVo.NOT_ENOUGH);
            resultVo.setTitle("当前可用票数不足");
            return resultVo;
        }
        VoteOrganizationInfo organizationInfo = voteOrganizationService.getOrgInfoByOrgCode(activityInfo.getOrgTypeId(), dto.getOrgCode());
        if (organizationInfo == null) {
            throw new BusinessException("选手信息不存在");
        }
        // 扣减用户投票数量
        dto.setNum(-VoteConstant.DEFAULT_VOTE_NUM);
        Pair<Boolean, String> re = userVoteService.updateVoteNum(dto);
        if (!re.getLeft()) {
            resultVo.setType(UserVoteResultVo.NOT_ENOUGH);
            resultVo.setTitle(re.getRight());
            return resultVo;
        }
        // 增加被投组织票数
        voteOrganizationService.updateOrgVote(activityInfo.getOrgTypeId(), dto.getOrgCode());
        // 更新被投组织redis全国榜
        activityVoteRedisService.incAllSchoolVote(dto.getActivityId(), organizationInfo.getOrgCode(), VoteConstant.DEFAULT_VOTE_NUM);
        // 更新被投组织redis省榜
        activityVoteRedisService.incProvinceSchoolVote(dto.getActivityId(), organizationInfo.getProvinceCode(), organizationInfo.getOrgCode(), VoteConstant.DEFAULT_VOTE_NUM);
        // 添加总的投票数量
        activityVoteRedisService.incTotalVoteNum(dto.getActivityId(), VoteConstant.DEFAULT_VOTE_NUM);
        // 添加用户邀请
        activityVoteService.updateVoteInviteRecord(dto.getActivityId(), dto.getUserId());
        // 添加投票明细
        activityVoteService.saveVoteDetail(dto.getActivityId(), dto.getUserId());
        // 更新用户投票个人榜
        double voteNum = activityVoteRedisService.incPersonalVote(dto.getActivityId(), dto.getUserId(), VoteConstant.DEFAULT_VOTE_NUM);
        long num = (long) voteNum;
        // 第一次投票
        if (num == 1) {
            // 添加报名信息
            dto.getUserPO().setSignUpVideo(true);
            wechatMiniQaService.updateAfterSignUpUserInfo(dto.getActivityId(), dto.getUserPO());
        }
        return resultVo;
    }

    /**
     * 组织搜索接口
     * @param dto
     * @return
     */
    public Page<OrgVoteInfoVo> getOrgPageInfo(OrgInfoSearchDTO dto) {
        Pair<Long, List<VoteOrganizationInfo>> result = voteOrganizationService.getOrgList(dto);
        PageRequest pageRequest = PageRequest.of(dto.getPage() - 1, dto.getPageSize());
        List<OrgVoteInfoVo> list = result.getRight().stream().map(item -> voteOrgConvert.orgToVoteInfoVo(item)).collect(Collectors.toList());
        return PageableExecutionUtils.getPage(list, pageRequest, () -> result.getLeft());
    }

    public void checkSchoolInfo(UserBaseInfoSaveDTO dto) {
        if (StringUtils.isBlank(dto.getUniversityId())) {
            return;
        }
        Query queryUni = new Query().addCriteria(Criteria.where("id").is(dto.getUniversityId()));
        UniversityInfo universityInfo = mongoTemplate.findOne(queryUni, UniversityInfo.class);
        if (universityInfo == null) {
            log.error("checkSchoolInfo userId={} school info not exist", dto.getUserId());
            throw new BusinessException("学校信息不存在");
        }
        dto.setUniversityName(universityInfo.getName());
        dto.setUniversityCode(universityInfo.getValue());
    }

    /**
     * 保存用户信息
     * @param dto
     * @return
     */
    public boolean saveUserInfo(UserBaseInfoSaveDTO dto) {
        // 验证码校验
        if (dto.getMustCode()) {
            CheckMobileVO req = new CheckMobileVO();
            req.setUserPO(RequestContext.getCurUser());
            req.setCode(dto.getVerifyCode());
            req.setMobile(dto.getMobile());
            req.setPaltform(dto.getPlatform());
            boolean re = userService.checkMobile(req);
            if (!re) {
                log.error("saveUserInfo userId={} verify code check error:{}", dto.getUserId());
                throw new BusinessException("验证码校验错误");
            }
        }
        UserPO userPO = dto.getUserPO();
        // 校验学校信息
        checkSchoolInfo(dto);
        // 更新用户基本信息
        userVoteService.saveUserVoteInfo(dto);
        // 修改报名信息
        wechatMiniQaService.updateAfterSignUpUserInfo(dto.getActivityId(), dto.getUserPO());
        // 有一个存在则更新扩展表
        if (StringUtils.isNotBlank(dto.getMobile()) || StringUtils.isNotBlank(dto.getUniversityId()) || StringUtils.isNotBlank(dto.getUserName())) {
            userPO.setUniversityId(dto.getUniversityId());
            userPO.setUniversityName(dto.getUniversityName());
            userPO.setMobile(dto.getMobile());
            userPO.setName(dto.getUserName());
            userInfoExtendService.saveOrUpdate(userPO);
        }
        return true;
    }
}
